#include "ptwrap.hpp"
#include <stdio.h>
#include <unistd.h>

class autoevent
{
public:
	// DEBUG to

// [[ex03ad]]
// DEBUG descr The pulse method for the auto-reset event, incompatible with timed wait.
	int pulse()
	{
		pw::lockmutex lm(cond_);
		if (cond_.sleepers_ > 0) {
			signaled_ = true;
			cond_.signal();
		} else {
			signaled_ = false;
		}
		return 0;
	}
// END

	// DEBUG from
	autoevent(bool signaled = false) :
		signaled_(signaled)
	{ }

	int wait()
	{
		pw::lockmutex lm(cond_);
		while (!signaled_)
			cond_.wait();
		signaled_ = false;
		return 0;
	}
	int trywait()
	{
		pw::lockmutex lm(cond_);
		if (!signaled_)
			return ETIMEDOUT;
		signaled_ = false;
		return 0;
	}
	int timedwait(const struct timespec &abstime)
	{
		pw::lockmutex lm(cond_);
		while (!signaled_) {
			if (cond_.timedwait(abstime) == ETIMEDOUT)
				return ETIMEDOUT;
		}
		signaled_ = false;
		return 0;
	}
	int signal()
	{
		pw::lockmutex lm(cond_);
		signaled_ = true;
		cond_.signal();
		return 0;
	}
	int reset()
	{
		pw::lockmutex lm(cond_);
		signaled_ = false;
		return 0;
	}

protected:
	pw::pmcond cond_; // contains both condition variable and a mutex
	bool signaled_; // semaphore has been signaled
};

// DEBUG {

autoevent ae;

class waiter : public pw::pwthread
{
public:
	// auto-start on construction and stop before destruction
	waiter()
	{
		start();
	}
	~waiter()
	{
		join();
	}
	void *execute()
	{
		ae.wait();
		fprintf(stderr, "wait succeeded\n");
		return 0;
	}
};

int main()
{
	ae.pulse();
	if (ae.trywait() == ETIMEDOUT)
		fprintf(stderr, "trywait failed as expected\n");

	{
		waiter w1;
		ae.signal();
	}
	{
		waiter w1;
		usleep(100*1000);
		ae.pulse();
	}

	ae.signal();
	ae.signal();
	if (ae.trywait() == 0)
		fprintf(stderr, "trywait succeeded as expected\n");
	if (ae.trywait() == ETIMEDOUT)
		fprintf(stderr, "trywait failed as expected\n");

	struct timespec endtime;
	clock_gettime(CLOCK_REALTIME, &endtime); // the current time
	if (ae.timedwait(endtime) == ETIMEDOUT)
		fprintf(stderr, "timedwait failed as expected\n");
	ae.signal();
	if (ae.timedwait(endtime) == 0)
		fprintf(stderr, "timedwait succeeded as expected\n");
	return 0;
}
// DEBUG }
/* Sample output:

trywait failed as expected
wait succeeded
wait succeeded
trywait succeeded as expected
trywait failed as expected
timedwait failed as expected
timedwait succeeded as expected

*/
